/*
  file.c
    Achieve some file functions
  BeginnerC
 */
#include "file.h"
/*
    WriteFile
      Write content to a file
    Argument
      file_name
        The target file path
      content
        The content want to write
    Return Value
      The bool value reflects the result
    BeginnerC
*/
bool WriteFile(const char *file_name, char *content)
{
    FILE *fp = NULL;
    unsigned size = 0;
    if (NULL == content)
    {
        return false;
    }
    size = strlen(content);
    if (0 == size)
    {
        return false;
    }
    fp = fopen(file_name, "w");
    if (NULL == fp)
    {
        return false;
    }
    fwrite(content, size, 1, fp);
    fclose(fp);
    return true;
}
/*
    FileCopy
      Copy a file
    Argument
      source
        The source file path
      target
        The target file path
    Return Value
      The bool value reflects the result
    BeginnerC
*/
bool FileCopy(const char *source, const char *target)
{
    int fd_source = 0, fd_target = 0;
    char *buffer = NULL;
    off_t file_size = 0;

    if ( !(fd_source = open(source, O_RDONLY)) )
    {
        return false;
    }
    if ( !(fd_target = open(target, O_WRONLY | O_TRUNC | O_CREAT)) )
    {
        close(fd_source);
        return false;
    }

    file_size = lseek(fd_source, 0, SEEK_END);
    lseek(fd_source, SEEK_SET, 0);

    buffer = (char*)calloc(sizeof(char), file_size);
    if (NULL == buffer)
    {
        close(fd_source);
        close(fd_target);
        return false;
    }

    read(fd_source, buffer, file_size);
    close(fd_source);
    write(fd_target, buffer, file_size);
    free(buffer);

    fchmod(fd_target, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
    close(fd_target);

    return true;
}
/*
    DirectoryCopy
      Copy a directory
    Argument
      source
        The source file path
      target
        The target file path
    Return Value
      The bool value reflects the result
    BeginnerC
*/
bool DirectoryCopy(const char *source, const char *target)
{
    DIR *directory = NULL;
    struct dirent *file = NULL;

    if (NULL == (directory = opendir(source)))
    {
        return false;
    }
    mkdir(target, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);

    while (NULL != (file = readdir(directory)))
    {
        char file_name_source[NAME_MAX] = {};
        char file_name_target[NAME_MAX] = {};

        // Generate the origin file name
        strcpy(file_name_source, source);
        strcat(file_name_source, "/");
        strcat(file_name_source, file -> d_name);

        // Generate the target file name
        strcpy(file_name_target, target);
        strcat(file_name_target, "/");
        strcat(file_name_target, file -> d_name);

        if (DT_REG == file -> d_type)
        {
            FileCopy(file_name_source, file_name_target);
        }
        else if (DT_DIR == file -> d_type)
        {
            if (!strcmp(file -> d_name, ".") || !strcmp(file -> d_name, ".."))
            {
                continue;
            }
            DirectoryCopy(file_name_source, file_name_target);
        }
        else
        {
            continue;
        }
    }
    closedir(directory);
    return true;
}
/*
    DirectoryRemove
      Remove a directory
    Argument
      target
        The target directory path
    Return Value
      The bool value reflects the result
    Note
      If the target directory doesn't exist, it will return true
    BeginnerC
*/
bool DirectoryRemove(const char *target)
{
    DIR *directory = NULL;
    struct dirent *file = NULL;

    if (-1 == access(target, F_OK))
    {
        return true;
    }
    if (NULL == (directory = opendir(target)))
    {
        return false;
    }

    while (NULL != (file = readdir(directory)))
    {
        char file_name_target[NAME_MAX] = {};

        // Generate the target file name
        strcpy(file_name_target, target);
        strcat(file_name_target, "/");
        strcat(file_name_target, file -> d_name);
        if (DT_DIR == file -> d_type)
        {
            if (!strcmp(file -> d_name, ".") || !strcmp(file -> d_name, ".."))
            {
                continue;
            }
            DirectoryRemove(file_name_target);
            rmdir(file_name_target);
        }
        else
        {
            unlink(file_name_target);
        }
    }
    closedir(directory);
    rmdir(target);
    return true;
}
/*
  FileContent
    Load the whole file
  Argument
      file_name
        The target file
  Return Value
    The file content
    NULL Failed
  BeginnerC
 */
char* FileContent(const char *file_name)
{
    char *result_file_content = NULL;
    unsigned long size = 0;
    FILE *fp = NULL;

    fp = fopen(file_name, "r");
    if (NULL == fp)
    {
        return NULL;
    }

    fseek(fp, 0, SEEK_END);
    size = ftell(fp);
    result_file_content = (char*)calloc(1, size + 1);
    if (NULL == result_file_content)
    {
        fclose(fp);
        return NULL;
    }
    rewind(fp);
    fread(result_file_content, size, 1, fp);
    fclose(fp);

    return result_file_content;
}
